# Anton Puiu, 332CA

## Tema 1 - Marketplace

### Resurse utilizate
In implementarea temei, am utilizat urmatoarele:
- O lista de liste, numita **consumers_cart**
- O lista de liste, numita **producers_list**
- O lista de produse, numita **available_products**

### Utilizarea resurselor
#### consumers_cart
Un **consumator** poate consuma obiecte din **Marketplace**, daca si numai daca acesta detine unul sau mai multe **cosuri de cumparaturi** in **Marketplace**.

Un **cos de cumparaturi** reprezinta o lista in lista **consumers_cart**. Acesta este reprezentat de pozitia in lista **consumers_cart**, care este in acelasi timp identificatorul acestuia.

Orice **consumator** va fi nevoit sa introduca intr-un **cos de cumparaturi**, prin intermediul metodei **add_to_cart**, un produs pus la vanzare de catre un **producator**. Apelul acestei metode va elimina din lista **available_products** produsul respectiv.

Pentru a **consuma** efectiv produsele disponibile in **Marketplace**, un **consumator** trebuie sa apeleze metoda **place_order**, care pentru fiecare produs din **cosul de cumparaturi**, va **sterge** produsul din **lista primului producator** ce are dispoinbil acel produs.

Un **produs** *p* se considera **rezervat** daca si numai daca *p* se afla in lista unui producator din lista **producers_list** *si* **nu** se afla in lista **available_products**

Un **produs** *p* se considera **disponibil** daca si numai daca *p* se afla in lista unui producator din lista **producers_list** *si* **se** afla in lista **available_products**

#### available_products
Orice **consumator** va putea extrage produse din lista **available_products**.

Atunci cand un **consumator** apeleaza metoda **remove_from_cart**, daca produsul respectiv se afla in **cosul de comparaturi** al **consumatorului**, atunci acesta va fi scos din **cosul de cumparaturi** si introdus in lista **available_products**.

#### producers_list
Un producator este inregistrat in **Marketplace**, daca si numai daca ii este asociata o lista in lista **producers_list**.

Identificatorul unui producator reprezinta **indexul** listei sale in lista **producers_list**.

Un producator va publica un nou produs in **Marketplace** prin intermediul listei asociate in lista **producers_list**.

De asemenea, orice produs publicat in **Marketplace** va fi introdus in lista **available_products**.

Un produs, al unui producator **k**, se considera *vandut*, daca si numai daca:
- Un client a apelat metoda **place_order** din **Marketplace**, iar printre produsele din cosul de cumparaturi ale consumatorului se afla un produs pus la vanzare de respectivul producator
- In lista de producatori, producatorul **k** este **primul** producator ce are disponibil pentru vanzare produsul dorit de consumatorul curent.

### Directive de sincronizare
A fost utilizat doar obiectul de tip **Lock** pentru izolarea zonelor critice, precum:
- **producers_list**
- **consumers_cart**
- **available_products**

#### Zone critice
##### producers_list
Prima zona critica pentru aceasta lista se regaseste in metoda **register_producer**, in care pentru a retine *id*-ul listei asociate unui **producator**, trebuie sa asiguram atomicitatea celor doua operatii:
```python
producer_id = len(self.producers_list)
self.producers_list.append([])
```

A doua zona critica se afla in metoda **place_order**, in care pentru a asigura eliminarea **produsului** disponibil la **primul producator** din **Marketplace**, este necesara suspendarea introducerii unor noi elemente in lista **producers_list**. Intrucat operatiile de adaugare/stergere dintr-o lista sunt thread-safe, nu este necesara introducerea **Lock**-urilor pentru aceste operatii.
```python
self.producer_lock.acquire()

for producer_list in self.producers_list:
    if not found_producer:
        for producer_product in producer_list:
            if producer_product == product:
                producer_list.remove(product)
                found_producer = True
    else:
        break

self.producer_lock.release()
```

##### consumers_cart
Zona critica pentru aceasta lista se regaseste in metoda **new_cart**, in care pentru a retine *id*-ul unui **cos de cumparaturi** asociat unui **consumator**, trebuie sa asiguram atomicitatea celor doua operatii:
```python
cart_id = len(self.consumers_cart)
self.consumers_cart.append([])
```

##### available_products
Zona critica pentru aceasta lista se regaseste in metoda **add_to_cart**, in care trebuie sa asiguram valabilitatea conditiei:
```python
if product in self.available_products:
    self.available_products.remove(product)
```
